package sortingRMI_client;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.Arrays;
import java.lang.reflect.Method;

import sortingRMI_server.ISortFactory;


@SuppressWarnings("unchecked")
public class SortClient {

	private static final int _UNSORTED_ARRAY_LENGTH = 1000;
	private static final Class<?> _CLASS_TO_FILL_UNSORTED_ARRAY = MuziekCD.class;
	private static final int _NUMBER_OF_SORTERS = 8; // 8 cores in workstation
	private ListJoiner lj;
	
	public static void main(String[] args) throws RemoteException, NotBoundException, InstantiationException, IllegalAccessException, ClassNotFoundException {
			
		if (_NUMBER_OF_SORTERS > (_UNSORTED_ARRAY_LENGTH/2)) {
			System.out.println("Your minimum array length should be at least double the amount of sorters!\n");
			System.exit(0);
		}

			Registry registry = LocateRegistry.getRegistry("127.0.0.1",10001);
			ISortFactory sf = (ISortFactory) registry.lookup("sf");
			SortClient sc = new SortClient();		
			
			sc.sort(sf);

	}
	
	private void sort(ISortFactory sf) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
		Class<?>[] params = new Class[2];	
		params[0] = int.class;
		params[1] = Class.class;

		Comparable[][] bucketsToBeSorted;
		
		Class<?> af = Class.forName("sortingRMI_client.ArrayFiller");
		Object ArrayFiller = af.newInstance();
		
		try {
			Method method = af.getDeclaredMethod("generateRandomList",params);
			ListJoiner lj = new ListJoiner();
			Comparable[] arrayToBeSorted = (Comparable[]) method.invoke(ArrayFiller,_UNSORTED_ARRAY_LENGTH,_CLASS_TO_FILL_UNSORTED_ARRAY);
			bucketsToBeSorted = splice(arrayToBeSorted);

			startSomeSortThreads(sf, lj, bucketsToBeSorted);

		} catch(Exception e){
			e.printStackTrace();
		}
	}
	
	
	private Comparable[][] splice(Comparable[] array) {
		ArrayList arrayAsList = new ArrayList(Arrays.asList(array));
		char tempChar;
		Comparable[][] bucketsFilled = new Comparable[_NUMBER_OF_SORTERS][];

		ArrayList abcd = new ArrayList();
		ArrayList efg = new ArrayList();
		ArrayList hij = new ArrayList();
		ArrayList klm = new ArrayList();
		ArrayList nop = new ArrayList();
		ArrayList qrs = new ArrayList();
		ArrayList tuv = new ArrayList();
		ArrayList wxyz = new ArrayList();
		
		for (Object o : arrayAsList) {
			tempChar = ((MuziekCD) o).getArtist().charAt(0);
			if (tempChar >= 'a' && tempChar <= 'd') {
				abcd.add(o);
			}
			else if (tempChar >= 'e' && tempChar <= 'g') {
				efg.add(o);
			}
			else if (tempChar >= 'h' && tempChar <= 'j') {
				hij.add(o);
			}
			else if (tempChar >= 'k' && tempChar <= 'm') {
				klm.add(o);
			}
			else if (tempChar >= 'n' && tempChar <= 'p') {
				nop.add(o);
			}
			else if (tempChar >= 'q' && tempChar <= 's') {
				qrs.add(o);
			}
			else if (tempChar >= 't' && tempChar <= 'v') {
				tuv.add(o);
			}
			else {
				wxyz.add(o);
			}
		}
		
		bucketsFilled[0] = (Comparable[]) abcd.toArray(new Comparable[abcd.size()]);
		bucketsFilled[1] = (Comparable[]) efg.toArray(new Comparable[efg.size()]);
		bucketsFilled[2] = (Comparable[]) hij.toArray(new Comparable[hij.size()]);
		bucketsFilled[3] = (Comparable[]) klm.toArray(new Comparable[klm.size()]);
		bucketsFilled[4] = (Comparable[]) nop.toArray(new Comparable[nop.size()]);
		bucketsFilled[5] = (Comparable[]) qrs.toArray(new Comparable[qrs.size()]);
		bucketsFilled[6] = (Comparable[]) tuv.toArray(new Comparable[tuv.size()]);
		bucketsFilled[7] = (Comparable[]) wxyz.toArray(new Comparable[wxyz.size()]);
		
		return bucketsFilled;
	}
	
	private void startSomeSortThreads(ISortFactory sf, ListJoiner lj, Comparable[][] bucketsToBeSorted) throws RemoteException {
		int i,n = 0;
		for (i = 0; i < _NUMBER_OF_SORTERS; i++) {
			for ( n = 0; n < bucketsToBeSorted[i].length; n++) {
					((MuziekCD) bucketsToBeSorted[i][n]).setThreadName(Integer.toString(i));
			}
				SorterThread thread  = new SorterThread(bucketsToBeSorted[i], ((Integer) i).toString());
				thread.addObserver(lj);
				thread.start();
			//}
		}
	}
}